#!/usr/bin/python
import sys
import os
import ConfigParser
import string
import zpfile
import utilszp

def usage(name):
	"""
	classica funzione per stampare come utilizzare lo script
	e le varie opzioni che possono essere incluse.
	
	@name e' il nome assegnato allo script.
	
	La funzione non ritorna nulla.
	"""
	sys.stdout.write("Usage: %s [ -c, --create | -i, --install ] filename\n\n"
	"  -c, --create [file name]\tCrea un file di configurazione zb da stdin\n"
	"  -i, --install [file name]\tInstalla il file zb indicato come parametro\n"
	"  -d, --debug\t\t\tDa utilizzare con --install, genera messaggi aggiuntivi\n"
	"  -h, --help\t\t\tMostra questo messaggio d'aiuto\n"
       "\n\nPensavi di trovare un messaggio divertente in fondo? Ti sbagliavi.\n" % name)
	
def check_prep():
	""" 
	check_prep si assicura che i comandi che programmi necessari
	alla compilazione, make, gcc e tar, siano presenti in /usr/bin 
	o in /usr/local/bin e siano richiamabili.
	
	La funzione non accetta parametri.
	
	La funzione ritorna:
	    True se i programmi sono stati trovati e sono eseguibili.
	    False se i programmi non sono stati trovati o non sono eseguibili.
	    In questo caso riporta anche un messaggio di errore.
	"""
	dir = (
	'/usr/bin',
	'/usr/local/bin'
	)
	commands = (
    'gcc', 
	'make',
	'tar'
	)
	for i in dir:
		for j in commands:
			abs = os.path.join(i, j)
			if os.path.exists(abs) and os.access(abs, os.X_OK):
				return True
			else:
				sys.stdout.write("errore: impossibile trovare %s, assicurati di avere istallato %s"
						 "e riprova.\n" % (j, j))
	return False
			
def check_c_file(dir, debug_session=False):
	""" 
	La funzione cerca il Makefile e il file configure, il primo indispensabile
	per compilare un tarball, l'altro opzionale per la compilazione. 
	
	@dir rappresenta la directory in cui cercare.
	    
	La funzione ritorna:
	    1 se sia il Makefile e il configure sono stati trovati.
	    0 se solo il Makefile e' stato trovato
	    esce mostrando un messaggio di errore in caso non sia stato trovato il Makefile. 
	"""
	if debug_session == True:
		print "Mi trovo in => %s " %dir
	if os.path.isfile(dir + "/Makefile") == False: #or os.path.isfile(dir + "/Makefile.am") == False: 
		sys.exit("errore: impossibile trovare il Makefile, non sara' possibile continuare con la compilazione.")
	else:
		if os.path.exists(dir + "/configure") and os.access(dir + "/configure", os.X_OK):
			return 1
		return 0
	
def check_bod(conf, debug_session=False):
	"""
	La funzione check_bod e' il cuore dello script. Controlla il file zb
	passato come argomento, analizza le suo informazioni e cerca errori.
	Crea una directory temporanea in cui scaricare i file specificati
	e compila i tarball con ./configure, make e make install al suo interno.
	
	@conf e' il file di configurazione passato come argomento.
	
	la funzione non ritorna niente, esce con un messaggio esplicativo in
	caso di errore.
	"""
	
	# directory soggetta a cambiamento durante lo sviluppo
	default_dev_dir = "/tmp/zephyr"
	
	if conf.has_section("info") == True:
		email = conf.get("info", "email")
		if email != " ":
			sys.stdout.write("ricorda: la tua email potra' eventualmente essere utilizzata da terzi"
					   "che utilizzeranno questo file per comunicare con te!\n")
	if conf.has_option("source", "source") == True:
		source_wget = conf.get("source", "source")
		sourcename_from_url = utilszp.get_package_from_url(source_wget)
		sourcename_without_ext = utilszp.get_name_without_ext(sourcename_from_url)
		if not os.path_exists(default_dev_dir):
			os.mkdir(default_dev_dir)
		os.chdir(default_dev_dir)
		sys.stdout.write("scarico i sorgenti (%s)...\n" % source_wget)
		if debug_session == True:
			wwget = ("wget -q %s" % source_wget).replace(" -q", "")
		else:
			wwget = "wget -q %s" % source_wget
		if utilszp.catch_error(wwget) == False:
			sys.exit("errore: impossibile scaricare il file %s. Assicurati che la tua connessione funzioni, "
				  "oppure contatta il fornitore di questo file per segnalare il bug." % source_wget)
	
	else:
		sys.exit("errore: il file non e' valido, assicurati che "
			          "rispetti le linee guida dei file zphbod, poi riprova.\n"
			          "Se hai scaricato questo file dai repository, puoi inviare una mail"
			          "all'autore per segnalare il bug.")
	confgr = 0 # variabile per il controllo di 'configure'	
	if conf.has_option("dependencies","dep1") == True:
		sys.stdout.write("attenzione, nel file sono specificate alcune dipendenze, verranno istallate.\n")
		dep = []
		tarballname = []
		print "scarico le dipendendenze necessarie ..."
		for opt in conf.options("dependencies"):
			dep[opt] = conf.get("dependencies", opt)
			sys.stdout.write("scaricamento di %s in corso ...\n" % dep[opt])
			tarballname[opt] = dep[opt]
			if(debug_session == False):
				dep[opt] = "wget -q " + dep[opt]
			else:
				dep[opt] = ("wget -q " + dep[opt]).replace(" -q", "") # rimuovo l'opzione quite di wget.
			if debug_session == False:
				if utilszp.catch_error(dep[opt]) == False:
					sys.exit("errore: impossibile scaricare il file %s. Assicurati che la tua connessione funzioni, "
						   "oppure contatta il fornitore di questo file per segnalare il bug." % tarballname[opt])
			else: 
				os.system(dep[opt])
			name_from_url = utilszp.get_package_from_url(tarballname[opt])
			name_without_ext = utilszp.get_name_without_ext(name_from_url)
			sys.stdout.write("estraggo %s ...\n" % name_from_url)
			utilszp.extract_tar(name_from_url)
			sys.stdout.write("mi sposto in %s ...\n" % name_without_ext)
			if debug_session == True:
				print "Mi trovo in => %s " % os.getcwd()
			os.chdir(name_without_ext)
			if conf.has_option("compiler-option","opt") == True:
				sys.stdout.write("acquisico informazioni sulla compilazione ...\n")
				sys.stdout.write("controllo l'esistenza di 'configure' ...\n")
				if check_c_file(os.getcwd()):
					confgr = 1
					sys.stdout.write("il file 'configure' e' stato trovato, procedo alla compilazione ...\n")
				else:
					sys.stdout.write("attenzione: il file 'configure' non e' stato trovato. Procedo comunque alla compilazione ...\n")
				# ora inizia il processo di compilazione, con configure (se trovato), make, e make install
				gcc_opt = "make CFLAGS='" + conf.get("compiler-option", "opt") + "'"
				if(confgr == 1): # se il configure e' stato trovato
					os.system("./configure")	
				if utilszp.catch_error(gcc_opt) == False:
					sys.exit("ops, qualcosa e' andato storto durante la compilazione!")
				else:
					os.system("make install")
				os.chdir("../") # mi sposto nella directory superiore, uscendo dalla cartella del pacchetto
	sys.stdout.write("la compilazione delle dipendenze e' stata completata!\n")
	#compilo il pacchetto principale
	sys.stdout.write("compilo il pacchetto principale (%s)\n" % source_wget)
	sys.stdout.write("estraggo %s ...\n" % sourcename_from_url)
	utilszp.extract_tar(sourcename_from_url)
	sys.stdout.write("mi sposto in %s ...\n" % sourcename_without_ext)
	os.chdir(sourcename_without_ext)
	if conf.has_option("compiler-option","opt") == True:
		sys.stdout.write("acquisico informazioni sulla compilazione ...\n")
		sys.stdout.write("controllo l'esistenza di 'configure' ...\n")
		if check_c_file(os.getcwd(), debug_session):
			confgr = 1
			sys.stdout.write("il file 'configure' e' stato trovato, procedo alla compilazione ...\n")
		else:
			sys.stdout.write("attenzione: il file 'configure' non e' stato trovato. Procedo comunque alla compilazione ...\n")
		# ora inizia il processo di compilazione, con configure (se trovato), make, e make install
		gcc_opt = "make CFLAGS='%s'" % conf.get("compiler-option", "opt")
		if(confgr == 1): # se il configure e' stato trovato
			os.system("./configure")
		if utilszp.catch_error(gcc_opt) == False:
			sys.exit("ops, qualcosa e' andato storto durante la compilazione!")
		else:
			os.system("make install")
		sys.stdout.write("la compilazione e' stata completata!\n")

def clean_package(file_zp):
	"""
	Funzione che utilizza make e la flag 'clean' che di solito
	rimuove i file che non verranno piu' utilizzati dopo la
	compilazione.
	
	@file_zp e' il nome del file con estensione aggiunta se non specificata
	dall'utente.
	
	la funzione non ritorna niente, esce con un messaggio esplicativo in
	caso di errore.
	"""
	
	
def create_from_stdin(file_zp):
	"""
	create_from_stdin si occupa di ottenere informazioni inserite
	dall'utente in stdin per creare un file zb valido ed utilizzabile.
	Controlla eventuali errori e offre la possibilita' di scegliere se
	inserire informazioni opzionali.
	Utilizza la classe zpfile per le operazioni su file zp.
	
	@file_zp e' il nome del file con estensione aggiunta se non specificata
	dall'utente.
	
	la funzione non ritorna niente, esce con un messaggio esplicativo in
	caso di errore.
	"""
	informations = {}
	dependencies = []
	sys.stdout.write("creo il file %s ...\n" % file_zp)
	#try:
	newzpfile = zpfile.ZpFile(file_zp)
	#except:
		#sys.exit("impossibile creare il file. Assicurati di avere permessi necessari per creare il file in questa directory.")
	ch = raw_input("vuoi inserire delle informazioni su di te nel file? [y/n]\n")
	while ch != 'y':
		if ch == 'n': 
			break
		ch = raw_input("errore: devi inserire 'y' per una risposta affermativa e 'n' per una risposta negativa.\n"
		"vuoi inserire delle informazioni su di te nel file? [y/n] ")
		ch.lower()
	if ch == 'y':
		informations["package_name"] = raw_input("inserisci il nome del pacchetto: ")
		informations["package_version"] = raw_input("inserisci la versione del pacchetto: ")
		informations["package_website"] = raw_input("inserisci il sito ufficiale del pacchetto: ")
		informations["author_name"] = raw_input("inserisci il nome dell'autore del file zp: ")
		informations["author_email"] = raw_input("inserisci l'email dell'autore del file zp: ")
		informations["zp_version"] = raw_input("inserisci la versione del file zp: ")
		informations["zp_date"] = raw_input("inserisci la data di creazione del file zb (gg/mm/aa) (premi invio"
				       "per inserire la data corrente):")
		newzpfile.insertInfo(informations)
	source = raw_input("inserisci l'url del pacchetto principale: ")
	newzpfile.insertSource(source)
	check = False
	while check == False:
		n_dep = raw_input("inserisci il numero di dipendenze che vuoi inserire: ")
		if n_dep.isdigit() == False:
			sys.stdout.write("errore: inserisci un numero corretto.\n")
			check = False
		else:
			check = True
	for n in xrange(0, int(n_dep)):
		url = raw_input("inserisci l'url la dipendenza numero %d:" % (n + 1))
		dependencies.append(url)
	newzpfile.insertDependencies(dependencies)
	comp_opt = raw_input("inserisci le opzioni di compilazione per GCC: ")
	newzpfile.insertCompilerOptions(comp_opt)
	sys.stdout.write("scrivo sul file %s le opzioni inserite ...\n" % file_zp)
	try:
		newzpfile.writeZp(file_zp)
	except:
		sys.exit("errore: impossibile completare la scrittura sul file %s" % file_zp)
	sys.stdout.write("scrittura completata! il file %s ora e' pronto per essere utilizzato.\n" % file_zp)

def main():
	if sys.argv[1] != "--help" or sys.argv[1] != "-h":
		if len(sys.argv) < 3:
			sys.exit(usage(sys.argv[0]))
                
	if sys.argv[1] == "--install" or sys.argv[1] == "-i":
		if os.getuid() != 0: # controllo se l'utente sia root per eseguire l'opzione --install
			sys.exit("errore: devi essere root per eseguire l'opzione --install!")
		sys.stdout.write("controllo la validita' del file %s ...\n" % sys.argv[2])
		if os.path.isfile(sys.argv[2]):
			if sys.argv[2].endswith(".zp"):			   
				sys.stdout.write("controllo se e' presente tutto l'occorrente per la compilazione...\n")
				if check_prep() == True:
					config = ConfigParser.ConfigParser()
					sys.stdout.write("analizzo il file %s ...\n" % sys.argv[2])
					config.read(sys.argv[2])
					if len(sys.argv) >= 4:
						if sys.argv[3] == "--debug" or sys.argv[3] == "-d":
							check_bod(config, True)
					else:
						check_bod(config)
				else:
					sys.exit() # il messaggio di errore viene riportato da check_prep()
			else:
				sys.exit("errore: il file %s non e' valido. Assicurati che %s abbia estensione '.zp' e riprova." % (sys.argv[2], sys.argv[2]))
		else:
			sys.exit("errore: impossibile trovare il file %s,\n" % sys.argv[2])
	elif sys.argv[1] == "--create" or sys.argv[1] == "-c":
		if sys.argv[2].endswith(".zp") == False:
			sys.argv[2] += ".zp"
		create_from_stdin(sys.argv[2])
	elif sys.argv[1] == "--email" or sys.argv[1] == "-e":
			if len(sys.argv) < 2:
				usage();
			if argv[2].endswith(".zp"):
				config = ConfigParser.ConfigParser()
				sys.stdout.write("analizzo il file %s ...\n" % sys.argv[2])
				config.read(sys.argv[2])
				if conf.has_section("info") == True:
					email = conf.get("info", "email")
					if email == "":
						sys.exit("errore: impossibile trovare l'indirizzo email nel file zp.")
				else:
					sys.exit("errore: impossibile trovare la sezione info nel file zp.")
			else:
				sys.exit("errore: il file %s non e' valido. Assicurati che %s abbia estensione '.zp' e riprova.\n" % (sys.argv[2], sys.argv[2]))
				
	elif sys.argv[1] == "--help" or sys.argv[1] == "-h":
		usage(sys.argv[0])
		sys.exit()
		
if __name__ == "__main__": main()
